1 module core_4_5; 2 import std.experimental.xml.dom : Node; 3 import defs; 4 import util; 5 6 enum IndexFile = "man4/html/index.php"; 7 enum PrependXMLFileLocation = "man4/"; 8 9 OGLFunctionFamily[] readInFunctionFamilies() { 10 import std.file : readText; 11 import std.experimental.xml; 12 13 string raw_input = readText(IndexFile); 14 OGLFunctionFamily[] ret; 15 16 auto domBuilder = raw_input 17 .lexer 18 .parser 19 .cursor((CursorError err){}) 20 .domBuilder; 21 domBuilder.setSource(raw_input); 22 domBuilder.buildRecursive; 23 auto dom = domBuilder.getDocument; 24 25 auto apiEntryPoints = dom.firstChild.childNodes.item(1).childNodes.item(1).firstChild.childNodes.item(2); 26 auto level2 = apiEntryPoints.childNodes.item(1); 27 28 foreach(level3parent; level2.childNodes) { 29 if (level3parent.nodeName != "li") 30 continue; 31 auto level3 = level3parent.childNodes.item(1); 32 ret.length += level3.childNodes.length; 33 34 size_t i = level3.childNodes.length; 35 F2: foreach(functag; level3.childNodes) { 36 auto atag = functag.childNodes.item(0); 37 char[] filename = cast(char[])atag.attributes.getNamedItem("href").nodeValue; 38 string value = atag.firstChild.nodeValue; 39 40 switch(filename) { 41 case "removedTypes.xhtml": 42 ret.length--; 43 i--; 44 continue F2; 45 default: 46 filename[$-4] = 'm'; 47 filename[$-3] = 'l'; 48 filename = filename[0 .. $-2]; 49 break; 50 } 51 52 filename = PrependXMLFileLocation ~ filename; 53 54 foreach(family; ret) { 55 if (family.fromFilename == filename) { 56 ret.length--; 57 i--; 58 continue F2; 59 } 60 } 61 62 ret[$-i] = OGLFunctionFamily(cast(string)filename, value); 63 i--; 64 } 65 } 66 67 foreach(ref family; ret) { 68 family.functions = family.readInFunctions; 69 } 70 71 return ret; 72 } 73 74 OGLFunction[] readInFunctions(ref OGLFunctionFamily family) { 75 import std.file : readText; 76 import std.conv : to; 77 import std.experimental.xml; 78 79 string raw_input = readText(family.fromFilename); 80 OGLFunction[] ret; 81 82 if (raw_input.length < 72) { 83 return null; 84 } else 85 raw_input = raw_input[71 .. $]; 86 87 auto domBuilder = raw_input 88 .lexer 89 .parser 90 .cursor((CursorError err){}) 91 .domBuilder; 92 domBuilder.setSource(raw_input); 93 domBuilder.buildRecursive; 94 auto dom = domBuilder.getDocument; 95 96 // 97 98 auto copyrightTags = dom.getElementsByTagName("copyright"); 99 if (copyrightTags !is null && copyrightTags.length > 0) { 100 auto copyright = copyrightTags[0]; 101 family.copyright = copyright.lastChild.firstChild.nodeValue ~ " " ~ copyright.firstChild.firstChild.nodeValue; 102 } 103 104 // 105 106 auto funcprototypes = dom.getElementsByTagName("funcsynopsis")[0].childNodes; 107 ret.length = funcprototypes.length; 108 109 size_t i; 110 foreach(funcprototype; funcprototypes) { 111 switch(funcprototype.nodeName) { 112 case "funcprototype": 113 break; 114 default: 115 ret.length--; 116 continue; 117 } 118 119 ret[i].returnType = funcprototype.firstChild.firstChild.nodeValue.fixTypePointer; 120 ret[i].name = funcprototype.firstChild.lastChild.firstChild.nodeValue; 121 122 ret[i].argNames.length = funcprototype.childNodes.length; 123 ret[i].argTypes.length = ret[i].argNames.length; 124 125 size_t j; 126 foreach(paramdef; funcprototype.childNodes) { 127 switch(paramdef.nodeName) { 128 case "paramdef": 129 break; 130 default: 131 ret[i].argNames.length--; 132 ret[i].argTypes.length--; 133 continue; 134 } 135 136 if (paramdef.firstChild.nodeValue.length > 0) { 137 ret[i].argTypes[j] = paramdef.firstChild.nodeValue.fixTypePointer; 138 139 if (ret[i].argTypes[j].length > 0 && ret[i].argTypes[j][$-1] == ' ') 140 ret[i].argTypes[j].length--; 141 142 if (paramdef.childNodes.length == 2) 143 ret[i].argNames[j] = paramdef.lastChild.firstChild.nodeValue; 144 } else 145 ret[i].argTypes[j] = paramdef.firstChild.firstChild.nodeValue.fixTypePointer; 146 147 j++; 148 } 149 150 i++; 151 } 152 153 // 154 155 auto refsect1 = dom.getElementsByTagName("refsect1"); 156 foreach(node; refsect1) { 157 if (node.attributes.getNamedItem("xml:id") is null) 158 continue; 159 160 switch(node.attributes.getNamedItem("xml:id").nodeValue) { 161 case "parameters": 162 auto varlistentries = node.childNodes.item(1).childNodes; 163 family.docs_parameters.length = varlistentries.length; 164 165 i = 0; 166 foreach(varlistentry; varlistentries) { 167 auto parameters = varlistentry.firstChild.childNodes; 168 auto paras = varlistentry.lastChild.childNodes; 169 170 family.docs_parameters[i].appliesToNames.length = parameters.length; 171 172 size_t j; 173 foreach(param; parameters) { 174 if (param.nodeName == "#text") { 175 family.docs_parameters[i].appliesToNames.length--; 176 continue; 177 } 178 family.docs_parameters[i].appliesToNames[j] = param.firstChild.nodeValue; 179 j++; 180 } 181 182 foreach (para; paras) 183 family.docs_parameters[i].documentation.evaluateDocs(para); 184 185 i++; 186 } 187 break; 188 189 case "description": 190 i = 0; 191 foreach(child; node.childNodes) { 192 i++; 193 if (i == 1) 194 continue; 195 family.docs_description.evaluateDocs(child); 196 } 197 break; 198 199 case "notes": 200 i = 0; 201 foreach(child; node.childNodes) { 202 i++; 203 if (i == 1) 204 continue; 205 family.docs_notes.evaluateDocs(child); 206 } 207 break; 208 209 case "seealso": 210 i = 0; 211 foreach(child; node.childNodes) { 212 i++; 213 if (i == 1) 214 continue; 215 family.docs_seealso.evaluateDocs(child); 216 } 217 break; 218 219 case "Copyright": 220 case "copyright": 221 i = 0; 222 foreach(child; node.childNodes) { 223 i++; 224 if (i == 1) 225 continue; 226 family.docs_copyright.evaluateDocs(child); 227 } 228 break; 229 230 case "versions": 231 // refsect1.informaltable.tgroup.tbody.trow.xi:include 232 auto xiinclude = node.childNodes.item(1).childNodes.item(0).childNodes.item(1).childNodes.item(0).childNodes.item(1); 233 string value = xiinclude.attributes.getNamedItem("xpointer").nodeValue; 234 235 // xpointer(/*/*[@role='20']/*) 236 family.introducedIn = cast(OGLIntroducedIn)(value["xpointer(/*/*[@role='".length .. $][0 .. 2].to!ushort); 237 238 break; 239 240 case "errors": 241 i = 0; 242 foreach(child; node.childNodes) { 243 i++; 244 if (i == 1) 245 continue; 246 family.docs_errors.evaluateDocs(child); 247 } 248 break; 249 250 default: 251 break; 252 } 253 } 254 255 // 256 257 return ret; 258 } 259 260 void evaluateDocs(ref OGLDocumentation parentContainer, Node!string current) { 261 OGLDocumentation next; 262 263 switch(current.nodeName) { 264 case "para": 265 next = OGLDocumentation(OGLDocumentationType.Paragraph); 266 goto case "$$container$$"; 267 case "title": 268 next = OGLDocumentation(OGLDocumentationType.Title); 269 goto case "$$container$$"; 270 271 case "constant": 272 next = OGLDocumentation(OGLDocumentationType.LookupConstant); 273 goto case "$$container$$"; 274 case "parameter": 275 next = OGLDocumentation(OGLDocumentationType.LookupParameter); 276 goto case "$$container$$"; 277 case "refentrytitle": 278 case "function": 279 next = OGLDocumentation(OGLDocumentationType.LookupFunction); 280 goto case "$$container$$"; 281 282 case "tgroup": 283 import std.conv : to; 284 next = OGLDocumentation(OGLDocumentationType.TableContainer); 285 next.value_numcols = current.attributes.getNamedItem("cols").nodeValue.to!int; 286 goto case "$$container$$"; 287 case "thead": 288 next = OGLDocumentation(OGLDocumentationType.TableHeader); 289 goto case "$$container$$"; 290 case "tbody": 291 next = OGLDocumentation(OGLDocumentationType.TableBody); 292 goto case "$$container$$"; 293 case "row": 294 next = OGLDocumentation(OGLDocumentationType.TableRow); 295 goto case "$$container$$"; 296 case "entry": 297 next = OGLDocumentation(OGLDocumentationType.TableEntry); 298 goto case "$$container$$"; 299 300 case "superscript": 301 next = OGLDocumentation(OGLDocumentationType.StyleSuperScript); 302 goto case "$$container$$"; 303 case "subscript": 304 next = OGLDocumentation(OGLDocumentationType.StyleSubScript); 305 goto case "$$container$$"; 306 307 case "term": 308 case "table": 309 case "informaltable": 310 next = OGLDocumentation(OGLDocumentationType.Container); 311 goto case "$$container$$"; 312 313 case "itemizedlist": 314 next = OGLDocumentation(OGLDocumentationType.IndexList); 315 goto case "$$container$$"; 316 case "listitem": 317 next = OGLDocumentation(OGLDocumentationType.IndexItem); 318 goto case "$$container$$"; 319 320 case "variablelist": 321 next = OGLDocumentation(OGLDocumentationType.List); 322 goto case "$$container$$"; 323 case "varlistentry": 324 next = OGLDocumentation(OGLDocumentationType.ListItem); 325 goto case "$$container$$"; 326 327 case "trademark": 328 if (current.attributes is null) 329 break; 330 if (current.attributes.getNamedItem("class").nodeValue == "copyright") 331 next = OGLDocumentation(OGLDocumentationType.Copyright); 332 else 333 next = OGLDocumentation(OGLDocumentationType.Trademark); 334 goto case "$$container$$"; 335 case "link": 336 next = OGLDocumentation(OGLDocumentationType.Link); 337 next.value_string = current.attributes.getNamedItem("xlink:href").nodeValue; 338 goto case "$$container$$"; 339 case "ulink": 340 next = OGLDocumentation(OGLDocumentationType.Link); 341 next.value_string = current.attributes.getNamedItem("url").nodeValue; 342 goto case "$$container$$"; 343 344 case "citerefentry": 345 next = OGLDocumentation(OGLDocumentationType.Container); 346 goto case "$$container$$"; 347 case "footnote": 348 next = OGLDocumentation(OGLDocumentationType.Footnote); 349 goto case "$$container$$"; 350 351 case "emphasis": 352 if (current.attributes is null) 353 break; 354 auto roleAttribute = current.attributes.getNamedItem("role"); 355 if (roleAttribute !is null) { 356 next = OGLDocumentation(OGLDocumentationType.StyleContainer, roleAttribute.nodeValue); 357 goto case "$$container$$"; 358 } else { 359 break; 360 } 361 case "code": 362 case "programlisting": 363 next = OGLDocumentation(OGLDocumentationType.StyleCode); 364 goto case "$$container$$"; 365 366 case "$$container$$": 367 auto children = current.childNodes; 368 foreach(childI; 0 .. children.length) { 369 next.evaluateDocs(children.item(childI)); 370 } 371 372 parentContainer.value_children ~= next; 373 break; 374 375 case "xi:include": 376 string newfile = PrependXMLFileLocation ~ current.attributes.getNamedItem("href").nodeValue; 377 378 import std.file : readText; 379 import std.experimental.xml; 380 381 string raw_input = readText(newfile); 382 auto domBuilder = raw_input 383 .lexer 384 .parser 385 .cursor((CursorError err){}) 386 .domBuilder; 387 domBuilder.setSource(raw_input); 388 domBuilder.buildRecursive; 389 auto dom = domBuilder.getDocument; 390 391 next = OGLDocumentation(OGLDocumentationType.Container); 392 393 auto root = dom.lastChild; 394 if (root.nodeName == "informaltable" || root.nodeName == "table") { 395 auto children = root.childNodes; 396 397 foreach(childI; 0 .. children.length) { 398 next.evaluateDocs(children.item(childI)); 399 } 400 401 parentContainer.value_children ~= next; 402 } else { 403 parentContainer.value_children ~= OGLDocumentation(OGLDocumentationType.Unknown, current.nodeName); 404 } 405 406 break; 407 408 case "inlineequation": 409 next = OGLDocumentation(OGLDocumentationType.InlineEquation); 410 auto children = current.childNodes; 411 foreach(childI; 0 .. children.length) { 412 next.evaluateDocs(children.item(childI)); 413 } 414 415 parentContainer.value_children ~= next; 416 break; 417 case "mml:apply": 418 case "informalequation": 419 case "mml:math": 420 parentContainer.evaluateDocs_MathML(current); 421 break; 422 423 424 case "#text": 425 parentContainer.value_children ~= OGLDocumentation(OGLDocumentationType.Text, current.nodeValue); 426 break; 427 428 case "#comment": 429 case "colspec": 430 break; 431 432 default: 433 parentContainer.value_children ~= OGLDocumentation(OGLDocumentationType.Unknown, current.nodeName); 434 break; 435 } 436 } 437 438 void evaluateDocs_MathML(ref OGLDocumentation parentContainer, Node!string current) { 439 OGLDocumentation next; 440 441 string nodeName = current.nodeName; 442 if (nodeName.length > 3 && nodeName[0 .. 4] == "mml:") 443 nodeName = nodeName[4 .. $]; 444 445 switch(nodeName) { 446 case "mi": 447 next = OGLDocumentation(OGLDocumentationType.MathML_MI); 448 if (current.attributes !is null && current.attributes.getNamedItem("mathvariant") !is null) 449 next.value_string = current.attributes.getNamedItem("mathvariant").nodeValue; 450 goto case "$$container$$"; 451 case "mfenced": 452 next = OGLDocumentation(OGLDocumentationType.MathML_mfenced); 453 if (current.attributes.getNamedItem("open") !is null) 454 next.value_string = current.attributes.getNamedItem("open").nodeValue; 455 if (current.attributes.getNamedItem("close") !is null) 456 next.value_string2 = current.attributes.getNamedItem("close").nodeValue; 457 goto case "$$container$$"; 458 case "mn": 459 next = OGLDocumentation(OGLDocumentationType.MathML_mn); 460 goto case "$$container$$"; 461 case "mrow": 462 next = OGLDocumentation(OGLDocumentationType.MathML_mrow); 463 goto case "$$container$$"; 464 case "msup": 465 next = OGLDocumentation(OGLDocumentationType.MathML_msup); 466 goto case "$$container$$"; 467 case "mo": 468 next = OGLDocumentation(OGLDocumentationType.MathML_mo); 469 goto case "$$container$$"; 470 case "msub": 471 next = OGLDocumentation(OGLDocumentationType.MathML_msub); 472 goto case "$$container$$"; 473 case "mfrac": 474 next = OGLDocumentation(OGLDocumentationType.MathML_mfrac); 475 goto case "$$container$$"; 476 case "mtable": 477 next = OGLDocumentation(OGLDocumentationType.MathML_mtable); 478 if (current.attributes !is null && current.attributes.length > 0 && current.attributes.getNamedItem("columnalign") !is null) 479 next.value_string = current.attributes.getNamedItem("columnalign").nodeValue; 480 goto case "$$container$$"; 481 case "mtr": 482 next = OGLDocumentation(OGLDocumentationType.MathML_mtr); 483 goto case "$$container$$"; 484 case "mtd": 485 next = OGLDocumentation(OGLDocumentationType.MathML_mtd); 486 if (current.attributes !is null && current.attributes.length > 0 && current.attributes.getNamedItem("columnalign") !is null) 487 next.value_string = current.attributes.getNamedItem("columnalign").nodeValue; 488 goto case "$$container$$"; 489 case "mtext": 490 next = OGLDocumentation(OGLDocumentationType.MathML_mtext); 491 if (current.attributes !is null && current.attributes.length > 0 && current.attributes.getNamedItem("mathvariant") !is null) 492 next.value_string = current.attributes.getNamedItem("mathvariant").nodeValue; 493 goto case "$$container$$"; 494 case "apply": 495 next = OGLDocumentation(OGLDocumentationType.MathML_apply); 496 goto case "$$container$$"; 497 case "mover": 498 next = OGLDocumentation(OGLDocumentationType.MathML_mover); 499 goto case "$$container$$"; 500 case "munderover": 501 next = OGLDocumentation(OGLDocumentationType.MathML_munderover); 502 goto case "$$container$$"; 503 case "msqrt": 504 next = OGLDocumentation(OGLDocumentationType.MathML_msqrt); 505 goto case "$$container$$"; 506 507 case "csymbol": 508 next = OGLDocumentation(OGLDocumentationType.MathML_csymbol); 509 goto case "$$container$$"; 510 511 case "math": 512 next = OGLDocumentation(OGLDocumentationType.MathMLContainer); 513 goto case "$$container$$"; 514 515 case "informalequation": 516 auto children = current.childNodes; 517 foreach(childI; 0 .. children.length) { 518 parentContainer.evaluateDocs_MathML(children.item(childI)); 519 } 520 break; 521 522 case "$$container$$": 523 auto children = current.childNodes; 524 foreach(childI; 0 .. children.length) { 525 next.evaluateDocs_MathML(children.item(childI)); 526 } 527 528 parentContainer.value_children ~= next; 529 break; 530 531 case "mspace": 532 next = OGLDocumentation(OGLDocumentationType.MathML_mspace); 533 next.value_string = current.attributes.getNamedItem("width").nodeValue; 534 parentContainer.value_children ~= next; 535 break; 536 537 case "floor": 538 next = OGLDocumentation(OGLDocumentationType.MathML_floor); 539 parentContainer.value_children ~= next; 540 break; 541 case "infinity": 542 next = OGLDocumentation(OGLDocumentationType.MathML_infinity); 543 parentContainer.value_children ~= next; 544 break; 545 546 default: 547 parentContainer.evaluateDocs(current); 548 break; 549 } 550 }